<HTML>
 
<!-- Mirrored from www.javapractices.com/apps/movies/javadoc/src-html/hirondelle/movies/main/MainWindow.html by HTTrack Website Copier/3.x [XR&CO'2010], Sun, 12 Jun 2011 17:30:20 GMT -->
<HEAD>
  <TITLE>
MainWindow.java
  </TITLE>
  <LINK REL ='stylesheet' TYPE='text/css' HREF='../../../../highlight.css' TITLE='Style'>
 </HEAD>
 <BODY>
<PRE>
<span class='keyword'>package</span> hirondelle.movies.main;<a name=line.1></a>
<a name=line.2></a>
<span class='keyword'>import</span> hirondelle.movies.LaunchApplication;<a name=line.3></a>
<span class='keyword'>import</span> hirondelle.movies.about.AboutAction;<a name=line.4></a>
<span class='keyword'>import</span> hirondelle.movies.edit.MovieActionAdd;<a name=line.5></a>
<span class='keyword'>import</span> hirondelle.movies.edit.MovieActionChange;<a name=line.6></a>
<span class='keyword'>import</span> hirondelle.movies.edit.MovieActionDelete;<a name=line.7></a>
<span class='keyword'>import</span> hirondelle.movies.edit.MovieTableModel;<a name=line.8></a>
<span class='keyword'>import</span> hirondelle.movies.exit.ExitAction;<a name=line.9></a>
<span class='keyword'>import</span> hirondelle.movies.util.Util;<a name=line.10></a>
<span class='keyword'>import</span> hirondelle.movies.util.ui.UiUtil;<a name=line.11></a>
<a name=line.12></a>
<span class='keyword'>import</span> java.awt.Dimension;<a name=line.13></a>
<span class='keyword'>import</span> java.awt.Toolkit;<a name=line.14></a>
<span class='keyword'>import</span> java.awt.event.ActionEvent;<a name=line.15></a>
<span class='keyword'>import</span> java.awt.event.MouseAdapter;<a name=line.16></a>
<span class='keyword'>import</span> java.awt.event.MouseEvent;<a name=line.17></a>
<span class='keyword'>import</span> java.awt.Color;<a name=line.18></a>
<span class='keyword'>import</span> java.util.logging.Logger;<a name=line.19></a>
<a name=line.20></a>
<span class='keyword'>import</span> javax.swing.*;<a name=line.21></a>
<span class='keyword'>import</span> javax.swing.event.ListSelectionEvent;<a name=line.22></a>
<span class='keyword'>import</span> javax.swing.event.ListSelectionListener;<a name=line.23></a>
<span class='keyword'>import</span> java.util.Locale;<a name=line.24></a>
<a name=line.25></a>
<span class='comment'>/**<a name=line.26></a>
 Main window for the application.<a name=line.27></a>
 <a name=line.28></a>
 &lt;P&gt;A menu bar, and a sortable table containing the user's list of movies.<a name=line.29></a>
 <a name=line.30></a>
 &lt;P&gt;Some applications would add a confirmation dialog when the user exits.<a name=line.31></a>
*/</span><a name=line.32></a>
<span class='keyword'>public</span> <span class='keyword'>final</span> <span class='keyword'>class</span> MainWindow {<a name=line.33></a>
  <a name=line.34></a>
  <span class='comment'>/** <a name=line.35></a>
   Return an instance of this class.<a name=line.36></a>
   <a name=line.37></a>
   &lt;P&gt;This class is made a singleton, since there is only one main window. <a name=line.38></a>
   Any caller can refresh the main window using<a name=line.39></a>
   &lt;PRE&gt;MainWindow.getInstance().refreshView();&lt;/PRE&gt;<a name=line.40></a>
   This lets the app avoid needing to pass around an object reference <a name=line.41></a>
   to the main window.<a name=line.42></a>
  */</span><a name=line.43></a>
  <span class='keyword'>public</span> <span class='keyword'>static</span> MainWindow getInstance() {<a name=line.44></a>
    <span class='keyword'>return</span> INSTANCE;<a name=line.45></a>
  }<a name=line.46></a>
  <a name=line.47></a>
  <span class='comment'>/**<a name=line.48></a>
   Build and display the main window.<a name=line.49></a>
   @param aUserName user name, as validated by <a name=line.50></a>
   {@link hirondelle.movies.login.LoginController}. <a name=line.51></a>
  */</span><a name=line.52></a>
  <span class='keyword'>public</span> <span class='keyword'>void</span> buildAndShow(String aUserName){<a name=line.53></a>
    fUserName = aUserName;<a name=line.54></a>
    fLogger.fine(<span class='literal'>"Building GUI for user : "</span> + aUserName);<a name=line.55></a>
    buildGui();<a name=line.56></a>
  }<a name=line.57></a>
  <a name=line.58></a>
  <span class='comment'>/** Refresh the display in response to changing database content. */</span><a name=line.59></a>
  <span class='keyword'>public</span> <span class='keyword'>void</span> refreshView(){<a name=line.60></a>
    fMovieTableModel.refreshView();<a name=line.61></a>
  }<a name=line.62></a>
  <a name=line.63></a>
  <span class='comment'>/** <a name=line.64></a>
   Return the user name passed to {@link #buildAndShow(String)}.<a name=line.65></a>
   <a name=line.66></a>
  &lt;P&gt;The user name can be accessed anywhere using :<a name=line.67></a>
  &lt;PRE&gt;MainWindow.getInstance().getUserName();&lt;/PRE&gt;<a name=line.68></a>
  */</span><a name=line.69></a>
  <span class='keyword'>public</span> String getUserName(){<a name=line.70></a>
    <span class='keyword'>return</span> fUserName;<a name=line.71></a>
  }<a name=line.72></a>
  <a name=line.73></a>
  <span class='comment'>// PRIVATE //<a name=line.74></a>
</span>  <a name=line.75></a>
  <span class='comment'>/** The single instance of this class. */</span><a name=line.76></a>
  <span class='keyword'>private</span> <span class='keyword'>static</span> MainWindow INSTANCE = <span class='keyword'>new</span> MainWindow();<a name=line.77></a>
  <a name=line.78></a>
  <span class='comment'>/** Empty constructor prevents the caller from creating an object. */</span><a name=line.79></a>
  <span class='keyword'>private</span> MainWindow() {  }<a name=line.80></a>
  <a name=line.81></a>
  <span class='keyword'>private</span> MovieTableModel fMovieTableModel;<a name=line.82></a>
  <span class='keyword'>private</span> JTable fMovieTable;<a name=line.83></a>
  <span class='keyword'>private</span> Action fChangeMovieAction;<a name=line.84></a>
  <span class='keyword'>private</span> Action fDeleteMovieAction;<a name=line.85></a>
  <span class='keyword'>private</span> String fUserName;<a name=line.86></a>
  <span class='keyword'>private</span> <span class='keyword'>static</span> <span class='keyword'>final</span> Logger fLogger = Util.getLogger(MainWindow.<span class='keyword'>class</span>);<a name=line.87></a>
  <a name=line.88></a>
  <span class='comment'>/** Build the user interface. */</span><a name=line.89></a>
  <span class='keyword'>private</span> <span class='keyword'>void</span> buildGui(){<a name=line.90></a>
    JFrame frame = <span class='keyword'>new</span> JFrame(<a name=line.91></a>
      LaunchApplication.APP_NAME + <a name=line.92></a>
      <span class='literal'>" - "</span> + fUserName.toUpperCase(Locale.ENGLISH)<a name=line.93></a>
    ); <a name=line.94></a>
    <a name=line.95></a>
    fMovieTableModel = <span class='keyword'>new</span> MovieTableModel();<a name=line.96></a>
    fMovieTable = <span class='keyword'>new</span> JTable(fMovieTableModel);<a name=line.97></a>
    fMovieTable.setBackground(Color.LIGHT_GRAY);<a name=line.98></a>
    <a name=line.99></a>
    buildActionsAndMenu(frame);<a name=line.100></a>
    buildContent(frame);<a name=line.101></a>
    <a name=line.102></a>
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<a name=line.103></a>
    placeInMiddlePartOfTheScreen(frame);<a name=line.104></a>
    addApplicationIcon(frame);<a name=line.105></a>
    UiUtil.centerAndShow(frame);<a name=line.106></a>
  }<a name=line.107></a>
<a name=line.108></a>
  <span class='comment'>/** Sort the table.  Listens for clicks on the JTableHeader. */</span><a name=line.109></a>
  <span class='keyword'>private</span> <span class='keyword'>final</span> <span class='keyword'>class</span> SortMovieTable <span class='keyword'>extends</span> MouseAdapter {<a name=line.110></a>
    <span class='keyword'>@Override</span> <span class='keyword'>public</span> <span class='keyword'>void</span> mouseClicked(MouseEvent aEvent) {<a name=line.111></a>
      fLogger.config(<span class='literal'>"Sorting the table."</span>);<a name=line.112></a>
      <span class='keyword'>int</span> columnIdx = fMovieTable.getColumnModel().getColumnIndexAtX(aEvent.getX());<a name=line.113></a>
      fMovieTableModel.sortByColumn(columnIdx);<a name=line.114></a>
    }<a name=line.115></a>
  }<a name=line.116></a>
  <a name=line.117></a>
  <span class='comment'>/** Show a dialog to edit a movie.  Listens for double-clicks on the JTable. */</span><a name=line.118></a>
  <span class='keyword'>private</span> <span class='keyword'>final</span> <span class='keyword'>class</span> LaunchEditMovieDialog <span class='keyword'>extends</span> MouseAdapter {<a name=line.119></a>
    <span class='keyword'>@Override</span> <span class='keyword'>public</span> <span class='keyword'>void</span> mouseClicked(MouseEvent aEvent) {<a name=line.120></a>
      <span class='keyword'>if</span>( aEvent.getClickCount() == <span class='literal'>2</span>) {<a name=line.121></a>
        fLogger.config(<span class='literal'>"Editing a movie."</span>);<a name=line.122></a>
        ActionEvent event = <span class='keyword'>new</span> ActionEvent(<span class='keyword'>this</span>, <span class='literal'>0</span>, <span class='literal'>""</span>);<a name=line.123></a>
        fChangeMovieAction.actionPerformed(event);<a name=line.124></a>
      }<a name=line.125></a>
    }<a name=line.126></a>
  }<a name=line.127></a>
  <a name=line.128></a>
  <span class='comment'>/** Enable edit and delete actions only when something is selected in the table. */</span><a name=line.129></a>
  <span class='keyword'>private</span> <span class='keyword'>final</span> <span class='keyword'>class</span> EnableEditActions <span class='keyword'>implements</span> ListSelectionListener {<a name=line.130></a>
    <span class='keyword'>public</span> <span class='keyword'>void</span> valueChanged(ListSelectionEvent aEvent) {<a name=line.131></a>
      fLogger.fine(<a name=line.132></a>
        <span class='literal'>"List selection changed. First:"</span> + aEvent.getFirstIndex() + <span class='literal'>" Last "</span> + aEvent.getLastIndex()<a name=line.133></a>
      );<a name=line.134></a>
      <span class='keyword'>if</span>( aEvent.getFirstIndex() != -<span class='literal'>1</span>) {<a name=line.135></a>
        fDeleteMovieAction.setEnabled(<span class='keyword'>true</span>);<a name=line.136></a>
        fChangeMovieAction.setEnabled(<span class='keyword'>true</span>);<a name=line.137></a>
      }<a name=line.138></a>
      <span class='keyword'>else</span> {<a name=line.139></a>
        fDeleteMovieAction.setEnabled(<span class='keyword'>false</span>);<a name=line.140></a>
        fChangeMovieAction.setEnabled(<span class='keyword'>false</span>);<a name=line.141></a>
      }<a name=line.142></a>
    }<a name=line.143></a>
  }<a name=line.144></a>
  <a name=line.145></a>
  <span class='comment'>/** Build the menu bar. */</span><a name=line.146></a>
  <span class='keyword'>private</span> <span class='keyword'>void</span> buildActionsAndMenu(JFrame aFrame) {<a name=line.147></a>
    JMenuBar menuBar = <span class='keyword'>new</span> JMenuBar();<a name=line.148></a>
<a name=line.149></a>
    JMenu fileMenu = <span class='keyword'>new</span> JMenu(<span class='literal'>"File"</span>);<a name=line.150></a>
    fileMenu.setMnemonic(<span class='literal'>'F'</span>); <a name=line.151></a>
    Action addMovieAction = <span class='keyword'>new</span> MovieActionAdd(aFrame);<a name=line.152></a>
    fileMenu.add(<span class='keyword'>new</span> JMenuItem(addMovieAction));<a name=line.153></a>
    fChangeMovieAction = <span class='keyword'>new</span> MovieActionChange(aFrame, fMovieTable, fMovieTableModel);<a name=line.154></a>
    fileMenu.add(<span class='keyword'>new</span> JMenuItem(fChangeMovieAction));<a name=line.155></a>
    fDeleteMovieAction = <span class='keyword'>new</span> MovieActionDelete(fMovieTable, fMovieTableModel);<a name=line.156></a>
    fileMenu.add(<span class='keyword'>new</span> JMenuItem(fDeleteMovieAction));<a name=line.157></a>
    <a name=line.158></a>
    Action exitAction = <span class='keyword'>new</span> ExitAction();<a name=line.159></a>
    fileMenu.add(<span class='keyword'>new</span> JMenuItem(exitAction));<a name=line.160></a>
    menuBar.add(fileMenu);<a name=line.161></a>
    <a name=line.162></a>
    JMenu helpMenu = <span class='keyword'>new</span> JMenu(<span class='literal'>"Help"</span>);<a name=line.163></a>
    helpMenu.setMnemonic(<span class='literal'>'H'</span>);<a name=line.164></a>
    helpMenu.add(<span class='keyword'>new</span> JMenuItem(<span class='keyword'>new</span> AboutAction(aFrame)));<a name=line.165></a>
    menuBar.add(helpMenu);<a name=line.166></a>
    <a name=line.167></a>
    aFrame.setJMenuBar(menuBar);<a name=line.168></a>
  }<a name=line.169></a>
  <a name=line.170></a>
  <span class='comment'>/** Expand the frame to fill the middel part of the screen. */</span><a name=line.171></a>
  <span class='keyword'>private</span> <span class='keyword'>void</span> placeInMiddlePartOfTheScreen(JFrame aFrame) {<a name=line.172></a>
    Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();<a name=line.173></a>
    Dimension halfScreen = <span class='keyword'>new</span> Dimension(<span class='literal'>2</span>*screen.width/<span class='literal'>3</span>, screen.height/<span class='literal'>2</span>);<a name=line.174></a>
    aFrame.setPreferredSize(halfScreen);<a name=line.175></a>
  }<a name=line.176></a>
<a name=line.177></a>
  <span class='comment'>/**<a name=line.178></a>
    Custom icon for the upper left corner of the frame.<a name=line.179></a>
    Not that a path relative to this class is used. <a name=line.180></a>
   */</span><a name=line.181></a>
  <span class='keyword'>private</span> <span class='keyword'>void</span> addApplicationIcon(JFrame aFrame) {<a name=line.182></a>
    ImageIcon icon = UiUtil.createImageIcon(<span class='literal'>"app_icon.png"</span>, <span class='literal'>"Application icon"</span>, <span class='keyword'>this</span>.getClass());<a name=line.183></a>
    aFrame.setIconImage(icon.getImage());<a name=line.184></a>
  }<a name=line.185></a>
<a name=line.186></a>
  <span class='comment'>/** Build the main content of the frame. */</span><a name=line.187></a>
  <span class='keyword'>private</span> <span class='keyword'>void</span> buildContent(JFrame aFrame) {<a name=line.188></a>
    <span class='comment'>//relative column widths<a name=line.189></a>
</span>    fMovieTable.getColumnModel().getColumn(<span class='literal'>0</span>).setPreferredWidth(<span class='literal'>100</span>);<a name=line.190></a>
    fMovieTable.getColumnModel().getColumn(<span class='literal'>1</span>).setPreferredWidth(<span class='literal'>20</span>);<a name=line.191></a>
    fMovieTable.getColumnModel().getColumn(<span class='literal'>2</span>).setPreferredWidth(<span class='literal'>20</span>);<a name=line.192></a>
    fMovieTable.getColumnModel().getColumn(<span class='literal'>3</span>).setPreferredWidth(<span class='literal'>200</span>);<a name=line.193></a>
    <a name=line.194></a>
    <span class='comment'>/* <a name=line.195></a>
    * Interesting: even though these methods are one-liners, it's still useful to create <a name=line.196></a>
    * them, since, from the point of view of the caller, they *greatly* clarify the intent, and <a name=line.197></a>
    * read at a higher level of abstraction. <a name=line.198></a>
    */</span><a name=line.199></a>
    clickOnHeaderSortsTable();<a name=line.200></a>
    doubleClickShowsEditDialog();<a name=line.201></a>
    rowSelectionEnablesActions();<a name=line.202></a>
    <a name=line.203></a>
    JScrollPane panel = <span class='keyword'>new</span> JScrollPane(fMovieTable);<a name=line.204></a>
    aFrame.getContentPane().add(panel);  <a name=line.205></a>
  }<a name=line.206></a>
<a name=line.207></a>
  <span class='keyword'>private</span> <span class='keyword'>void</span> clickOnHeaderSortsTable() {<a name=line.208></a>
    fMovieTable.getTableHeader().addMouseListener(<span class='keyword'>new</span> SortMovieTable());<a name=line.209></a>
  }<a name=line.210></a>
  <a name=line.211></a>
  <span class='keyword'>private</span> <span class='keyword'>void</span> doubleClickShowsEditDialog() {<a name=line.212></a>
    fMovieTable.addMouseListener( <span class='keyword'>new</span> LaunchEditMovieDialog() );<a name=line.213></a>
  }<a name=line.214></a>
<a name=line.215></a>
  <span class='keyword'>private</span> <span class='keyword'>void</span> rowSelectionEnablesActions() {<a name=line.216></a>
    fMovieTable.getSelectionModel().addListSelectionListener( <span class='keyword'>new</span> EnableEditActions() );<a name=line.217></a>
  }<a name=line.218></a>
}<a name=line.219></a>
       <a name=line.220></a>
</PRE><a name=line.221></a>
 </BODY><a name=line.222></a>
<HTML><a name=line.223></a>
